﻿using Modules;
using Modules.Project;
using PmSoft.ApplicationContext;
using PmSoft.Exceptions;
using PmSoft.Quartz;
using Quartz;
using static Modules.Payroll.PayrollConstants;
using static Modules.Project.ProjectConstants;

namespace ManagementApi.Jobs
{
    /// <summary>
    /// 项目状态变更定时任务
    /// </summary>
    [DisallowConcurrentExecution]//不可并行执行
    [JobDescription("0 0 00 * * ?")]//必须每天0点执行
    //[JobDescription("0 */1 * * * ?")]//测试1分钟执行1次
    public class ProjectStatusChangeJob : IJob
    {
        private readonly ProjectLockOutService projectLockOutService;
        private readonly ProjectService projectService;
        private readonly ProjectGuaranteeRefundService projectGuaranteeRefundService;
        private readonly IApplicationContext applicationContext;
        private readonly ILogger logger;

        public ProjectStatusChangeJob(ProjectLockOutService projectLockOutService, ProjectService projectService,
ProjectGuaranteeRefundService projectGuaranteeRefundService, ILogger<ProjectStatusChangeJob> logger, IApplicationContext applicationContext)
        {
            this.projectLockOutService = projectLockOutService;
            this.projectService = projectService;
            this.projectGuaranteeRefundService = projectGuaranteeRefundService;
            this.logger = logger;
            this.applicationContext = applicationContext;
        }

        public Task Execute(IJobExecutionContext context)
        {
            IEnumerable<ProjectLockOut> projectLockOuts = projectLockOutService.GetProjectLockOutsByStatus(停复工申请状态.停工);

            #region 停工
            IEnumerable<ProjectLockOut> locks = projectLockOuts.Where(a => a.JobStatus == 0 && a.AuditType == 审核类型.已完结 && a.PlanStartDate?.Date == DateTime.Now.Date);
            if (locks.Any())
            {
                foreach (var item in locks)
                {
                    projectLockOutService.Lock(item);
                }
            }
            #endregion

            #region 复工
            IEnumerable<ProjectLockOut> outs = projectLockOuts.Where(a => a.JobStatus == 1 && a.AuditType == 审核类型.已完结 && a.PlanEndDate?.Date == DateTime.Now.Date);
            try
            {

                if (outs.Any())
                {
                    //开始事务
                    applicationContext.Transaction.Begin();
                    foreach (var item in outs)
                    {
                        item.EndDate = DateTime.Now.Date;
                        projectLockOutService.Update(item);
                        ProjectLockOut insertEntity = new()
                        {
                            ProjectId = item.ProjectId,
                            Status = 停复工申请状态.复工,
                            EndDate = DateTime.Now.Date,
                            Reason = "停工时间已到，系统自动复工",
                            JobStatus = 1,
                            CreateTime = DateTime.Now,
                            JobRunTime = DateTime.Now
                        };
                        projectLockOutService.Out(insertEntity);
                    }
                    applicationContext.Transaction.Complete();//提交事务
                }
            }
            catch (Exception ex)
            {
                applicationContext.Transaction.Abort();//回滚事务
                logger.LogError(ex, $"复工脚本执行失败");
                throw new BusinessException("复工脚本执行失败");
            }
            #endregion

            #region 在建
            IEnumerable<ProjectInfo> projectInfos = projectService.GetProjectInfosByStatus(项目状态.筹备).Where(a => a.ContractStartDate.Date >= DateTime.Now.Date);
            foreach (var item in projectInfos)
            {
                projectService.UpdateProjectStatus(item.ProjectId, 项目状态.在建, item.ContractStartDate);
            }
            #endregion

            #region 自动退还保证金
            IEnumerable<ProjectGuaranteeRefund> projectGuaranteeRefunds = projectGuaranteeRefundService.GetProjectGuaranteeRefundsByStatus(保证金退还状态.待退还).Where(a => a.RefundTime.Value.Date == DateTime.Now.Date);
            foreach (var item in projectGuaranteeRefunds)
            {
                projectGuaranteeRefundService.RefundPayment(item);
            }
            #endregion

            return Task.CompletedTask;
        }
    }
}
